<template>
  <div id="cesiumContainer"></div>
</template>

<script setup lang="ts">
import withBase from '@jl/common/src/utils/path';
import { round } from 'lodash';
import { IResource } from '@/api/resource/types';
import { addLayer } from '@/service';
import { retFilePath } from '@/utils';
import { useSettingStore } from '@/store/setting';

defineOptions({
  name: 'Cesium',
});

interface IProps {
  resourceDetail: null | IResource;
}

const props = withDefaults(defineProps<IProps>(), {
  resourceDetail: null,
});

// 比例尺
const distanceLabel = ref<string>('');
// 默认场景加载状态
let defaultSceneLoadComplete = false;
const settingStore = useSettingStore();

const init = async () => {
  const { CIMUP, Cesium } = window;

  const cimInstance = CIMUP.CimEngine.instance;

  window.cimInstance = cimInstance;

  await settingStore.getMapToken();

  cimInstance.init({
    config: {
      gisContainer: 'cesiumContainer',
      map: '谷歌',
      options: {
        animation: false,
        timeline: false,
        clock: true,
        hours: 11,
        minutes: 30,
        delay: 0,
      },
      mapObject: {
        view: {
          longitude: 113.92878028208328,
          latitude: 30.089004097298577,
          height: 10000371.007221604,
          duration: 3,
          heading: 6.2831853071795765,
          pitch: -1.570782970133429,
          maxDistance: 10000000,
          initViewStatically: true,
        },
        light: {
          shadows: true,
          size: 4096,
          softShadows: true,
          enableLighting: true,
          lightType: 'sunlight',
          color: '#FFFFFF',
        },
        layers: [
          {
            enable: true,
            index: 0,
            type: 'base',
            mapType: 'SINGLEIMAGE',
            dataSourceUrl: withBase() + '/images/globe.png',
            extent: [-180, -90, 180, 90],
          },
          {
            enable: true,
            index: 1,
            type: 'image',
            name: '天地图影像',
            source: 'tianditu',
            dataSourceUrl:
              'http://t0.tianditu.gov.cn/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=' +
              settingStore.token,
            maximumLevel: 18,
            minimumLevel: 1,
            icon: 'tdt-yx',
          },
        ],
      },
    },
  });
  cimInstance.eventApi.addEventListener('scene_tile_loaded', async () => {
    if (!defaultSceneLoadComplete) {
      defaultSceneLoadComplete = true;
      loadSource();
    }
  });
  cimInstance.eventApi.addEventListener('camera_change', function () {
    const scaleObj = cimInstance.api.getSceneScale();
    if (scaleObj) {
      distanceLabel.value = scaleObj.distanceLabel;
    }
    // console.log('比例尺----', scaleObj);
    const cameraParam = cimInstance.api.getCameraParameter();
    // console.log('指北针---', cameraParam.heading * Cesium.Math.DEGREES_PER_RADIAN);
  });
};

function loadSource() {
  const { cimInstance } = window;
  const { Cesium } = window;

  const resource: any = props.resourceDetail;
  let modelJson: any = null;
  let modelAttr: any = null;
  const centerPosition = ['gltf', 'jlg'].includes(resource.fileType)
    ? [121.50848439013963, 31.37453317071912, 10]
    : cimInstance.api.screenToDegrees({
        x: round(document.body.offsetWidth / 2),
        y: round(document.body.offsetHeight / 2),
      });
  console.log(resource, centerPosition);
  if (resource.fileType === 'gltf') {
    modelJson = {
      enable: true,
      name: resource.fileResName + '_gltf_' + Math.random().toString().split('.')[1],
      type: 'gltfmodel',
      positions: [[centerPosition[0], centerPosition[1], 5]],
      dataSourceUrl: retFilePath(resource.resUrl),
      scale: 1,
      rotation: [0, 0, 0],
      createType: 'primitive',
      shadowsType: 1,
    };
    modelAttr = {
      position: modelJson.positions[0],
      translation: [0, 0, 0],
      rotation: modelJson.rotation,
      scale: modelJson.scale,
      color: '',
    };
  }
  if (resource.fileType === '_3dtiles') {
    modelJson = {
      enable: true,
      name: resource.fileResName + '_tileset_' + Math.random().toString().split('.')[1], // 'tileset',
      type: 'tileset', // 对应图层 osgb 3dtiles
      dataSourceUrl: retFilePath(resource.resUrl),
      offset: [0, 0, 0],
      rotation: [0, 0, 0],
      scale: 1,
      flyTo: true,
    };
    modelAttr = {
      position: modelJson?.translation,
      translation: [0, 0, 0],
      rotation: modelJson?.rotation,
      scale: modelJson?.scale,
      color: '',
    };
  }
  if (resource.fileType === 'json') {
    Cesium.Resource.fetchJson({ url: retFilePath(resource.resUrl) }).then((res: any) => {
      const type = res?.features[0].geometry.type || '';
      let jsonType = '';
      switch (type) {
        case 'Point':
          jsonType = 'point';
          modelJson = {
            enable: true,
            type: jsonType,
            name: resource.fileResName + '_point_' + Math.random().toString().split('.')[1], // 'tileset',
            dataSourceUrl: retFilePath(resource.resUrl),
            size: 10,
            color: '#FF0000',
            outlineColor: '#FFFF00',
            outlineWidth: 1,
            flyTo: true,
            // scaleByDistanceArray: [10000, 0.5, 50000, 2],
            // translucencyByDistanceArray: [10000, 0.5, 50000, 1],
            // disableDepthTestDistance: Number.POSITIVE_INFINITY,
            // minDisplayDistance: 0,
            // maxDisplayDistance: 10000000,
            // height: 1,
          };
          modelAttr = {
            // size: 10,
            color: '#FF0000',
            outlineColor: '#FFFF00',
            outlineWidth: 1,
            // scaleByDistanceArray: undefined,
            // translucencyByDistanceArray: undefined,
            // minDisplayDistance: undefined,
            // maxDisplayDistance: undefined,
            // height: undefined,
          };
          break;

        case 'LineString':
          jsonType = 'polyline';
          modelJson = {
            enable: true,
            name: resource.fileResName + '_polyline_' + Math.random().toString().split('.')[1], // 'tileset',
            type: jsonType,
            dataSourceUrl: retFilePath(resource.resUrl),
            color: '#FFFF00',
            width: 10,
            createType: 'entity',
            flyTo: true,
            // minDisplayDistance: 1000,
            // maxDisplayDistance: 50000
          };
          modelAttr = {
            color: '#FF0000',
            width: 10,
            // minDisplayDistance: 1000,
            // maxDisplayDistance: 50000
          };
          break;

        case 'MultiPolygon':
          jsonType = 'polygon';
          modelJson = {
            enable: true,
            name: resource.fileResName + '_polygon_' + Math.random().toString().split('.')[1], // 'tileset',
            type: 'polygon',
            dataSourceUrl: retFilePath(resource.resUrl),
            fillColor: '#FF0000',
            createType: 'entity',
            flyTo: true,
          };
          modelAttr = {
            fillColor: '#FF0000',
            minDisplayDistance: 0,
            maxDisplayDistance: undefined,
          };
          break;

        default:
          jsonType = '';
          break;
      }
      executeFunc(modelJson, resource, modelAttr);
    });
    return;
  }
  if (resource.fileType === 'jlg') {
    const fileName = resource.resUrl.split('/').pop();
    modelJson = {
      enable: true,
      name: resource.fileResName + '_bimModel_' + Math.random().toString().split('.')[1],
      type: 'bimModel',
      url: retFilePath(resource.resUrl),
      texturePath: retFilePath(resource.resUrl.replace(fileName, 'textures/')),
      showStats: false,
      translation: [centerPosition[0], centerPosition[1], 5],
      rotation: [0, 0, 0],
      scale: 1,
      loaderWorkerUrl: '/cimupresource/shouqiandemo/zhengtai/bim/upbim.worker.js',
      unit: 'm',
      dracoUrl: '/cimupresource/shouqiandemo/zhengtai/bim/draco_decoder.js',
      flyTo: true,
    };
    modelAttr = {
      position: modelJson.transition,
      translation: [0, 0, 0],
      rotation: [0, 0, 0],
      scale: 1,
      color: '',
    };
  }
  if (resource.fileType === 'tif_dom') {
    if (resource.configJson) {
      const configJson = JSON.parse(resource.configJson);
      if (configJson.Method === 'XyzCut') {
        const extent = configJson.Extent ? getExtent(configJson.Extent) : [];
        modelJson = {
          enable: true,
          name: resource.fileResName + '_image_' + Math.random().toString().split('.')[1],
          type: 'image',
          source: 'fileserver',
          dataSourceUrl: retFilePath(resource.resUrl),
          maximumLevel: 18,
          minimumLevel: 1,
          brightness: 1,
          saturation: 1,
          contrast: 1,
          extent: extent,
          flyTo: true,
        };
      } else {
        const extent = configJson.Extent ? getExtent(configJson.Extent) : [];
        console.log('--影像图层范围--', extent);
        const arr = resource.resUrl.split('?');
        const url = arr[0],
          param: any = {};
        if (arr[1] && arr[1].split('&').length > 0) {
          arr[1].split('&').forEach((ele: string) => {
            param[ele.split('=')[0]] = ele.split('=')[1];
          });
        }
        modelJson = {
          enable: true,
          name: resource.fileResName + '_image_' + Math.random().toString().split('.')[1],
          type: 'image',
          source: 'geoserver',
          dataSourceUrl: `/${url}?`,
          layers: param.layers || '',
          format: param.format || 'image/png',
          srs: param.srs || 'EPSG:4326',
          serviceVer: param.serviceVer || '1.1.0',
          maximumLevel: 18,
          minimumLevel: 1,
          brightness: 1,
          saturation: 1,
          contrast: 1,
          extent,
        };
      }
    } else {
      return;
    }
    modelAttr = {
      brightness: 1,
      saturation: 1,
      contrast: 1,
    };
  }
  if (resource.fileType === 'tif_dem') {
    if (resource.configJson) {
      const configJson = JSON.parse(resource.configJson);
      if (configJson.Method === 'LayerRele') {
        const extent = configJson.Extent ? getExtent(configJson.Extent) : [];
        console.log('--地形图层范围--', extent);
        const arr = resource.resUrl.split('?');
        const url = arr[0],
          param: any = {};
        if (arr[1] && arr[1].split('&').length > 0) {
          arr[1].split('&').forEach((ele: string) => {
            param[ele.split('=')[0]] = ele.split('=')[1];
          });
        }
        modelJson = {
          enable: true,
          name: resource.fileResName + '_image_' + Math.random().toString().split('.')[1],
          type: 'image',
          source: 'geoserver',
          dataSourceUrl: `/${url}?`,
          layers: param.layers || '',
          format: param.format || 'image/png',
          srs: param.srs || 'EPSG:4326',
          serviceVer: param.serviceVer || '1.1.0',
          maximumLevel: 18,
          minimumLevel: 1,
          brightness: 1,
          saturation: 1,
          contrast: 1,
          extent,
        };
      }
    } else {
      return;
    }
    modelAttr = {
      brightness: 1,
      saturation: 1,
      contrast: 1,
    };
  }

  executeFunc(modelJson, resource, modelAttr);
}

function getExtent(str: string) {
  let extent = [];
  if (str.includes('EPSG')) {
    extent = str.replace('[EPSG:4326]', '').trim().split(',');
  } else {
    extent = str.trim().split(',');
  }
  extent = extent.map((v: string) => Number(v)).sort((a: number, b: number) => a - b);
  const Xmin = extent[2],
    Xmax = extent[3],
    Ymin = extent[0],
    Ymax = extent[1];

  return [Xmin, Ymin, Xmax, Ymax];
}

function executeFunc(modelJson: any, resource: IResource, modelAttr: any) {
  const { cimInstance } = window;
  if (!modelJson) {
    return;
  }
  const layerParam: any = {
    code: Math.random().toString().split('.')[1],
    show: true,
    json: modelJson,
    name: resource.fileResName,
    layerName: modelJson.name,
    desc: '',
    type: modelJson.type,
  };
  if (modelAttr) {
    layerParam.attr = modelAttr;
  }
  if (layerParam.type === 'gltfmodel') {
    cimInstance.api.addGLTFModel({ ...layerParam.json, readyCall: importModelCallBack });
  }
  if (layerParam.type === 'tileset') {
    cimInstance.api.add3DTilesModel(layerParam.json);
  }
  if (layerParam.type === 'point') {
    cimInstance.api.addPointLayer(layerParam.json);
  }
  if (layerParam.type === 'polyline') {
    cimInstance.api.addPolylineLayer(layerParam.json);
  }
  if (layerParam.type === 'polygon') {
    cimInstance.api.addPolygonLayer(layerParam.json);
  }
  if (layerParam.type === 'bimModel') {
    cimInstance.api.addLayerByType({
      ...layerParam.json,
      loadConfig: [
        {
          title: '',
          url: layerParam.json.url,
          texturePath: layerParam.json.texturePath,
          translation: layerParam.json.translation,
          unit: 'm',
          rotation: layerParam.json.rotation,
          scale: 1,
          useMaterial: true,
        },
      ],
    });
  }
  if (['image'].includes(layerParam.type)) {
    cimInstance.api.addLayerByType(layerParam.json);
    setTimeout(() => {
      cimInstance.api.flyToLayer(layerParam.json.name);
    }, 200);
  }
}

function importModelCallBack(layer: any) {
  const { cimInstance } = window;
  if (['div'].includes(layer.type)) {
    const params = cimInstance.api.getCameraParameter();
    cimInstance.api.lookModel(
      layer.attr.position[0],
      layer.attr.position[1],
      layer.attr.position[2],
      params.heading,
      params.patch,
      100,
      0.7
    );
    return;
  }
  cimInstance.api.flyToLayer(layer.name);
}

onMounted(() => {
  init();
});
</script>

<style lang="less" scoped>
#cesiumContainer {
  height: 100%;
}
</style>
